공공데이터 포털에서 데이터 가져오기를 통해 입수한 데이터를 후속 시각화와 모형개발 작업을 위해 깔끔한 정제작업을 수행한다. 특히, 2020-11-06 중복된 행이 포함되어 중복 제거작업을 선행하여 처리한다.
library(tidyverse)
library(httr)
library(rvest)
library(glue)
library(lubridate)
covid_age_gender_dat <- read_rds("data/covid_age_gender.rds")
covid_age_gender_df <- covid_age_gender_dat %>%
mutate(날짜 = ymd_hms(날짜) %>% as.Date(.)) %>%
mutate(across(contains("율"), .fns = function(x) as.numeric(x) / 100)) %>%
mutate(검사자 = 확진자 / 감염율) %>%
distinct(., .keep_all = TRUE) %>% ## 2020-11-06 중복된 행이 포함되어 중복 제거작업
select(날짜, 검사자, everything())
## 성별 ----
covid_gender_df <- covid_age_gender_df %>%
filter(str_detect(구분, pattern = "(남성)|(여성)")) %>%
select(날짜, 구분, everything())
# covid_gender_df
## 연령별 ----
covid_age_df <- covid_age_gender_df %>%
filter(!str_detect(구분, pattern = "(남성)|(여성)"))
covid_age_df# A tibble: 2,332 x 7
날짜 검사자 확진자 감염율 사망자 치명율 구분
<date> <dbl> <int> <dbl> <int> <dbl> <chr>
1 2020-12-25 54718. 1844 0.0337 0 0 0-9
2 2020-12-25 54799. 3403 0.0621 0 0 10-19
3 2020-12-25 54767. 9042 0.165 0 0 20-29
4 2020-12-25 54752. 6948 0.127 3 0.0039 30-39
5 2020-12-25 54769. 7695 0.140 7 0.0091 40-49
6 2020-12-25 54773. 10248 0.187 30 0.0388 50-59
7 2020-12-25 54777. 8589 0.157 90 0.116 60-69
8 2020-12-25 54766. 4321 0.0789 227 0.294 70-79
9 2020-12-25 54806. 2680 0.0489 416 0.538 80 이상
10 2020-12-24 53482. 1797 0.0336 0 0 0-9
# ... with 2,322 more rows
본격적인 코로나19 작업을 수행하기 이전에 데이터에 대한 전반적인 이해를 높이기 위해 시각화를 한다. 이를 통해서 2020년 4월 초기 서비스를 오픈하면서 일부 기술적인 문제로 데이터가 없는 문제가 발견되어 결측값을 보정해야만 된다.
library(timetk)
covid_confirmed_g <- covid_age_df %>%
group_by(날짜) %>%
timetk::summarise_by_time(.date_var = 날짜,
.by = "day",
확진자 = sum(확진자),
검사자 = sum(검사자)) %>%
ungroup() %>%
filter(날짜 < "2020-05-01") %>%
pivot_longer(-날짜) %>%
plot_time_series(.date_var = 날짜,
.value = value,
.color_var = name,
# .facet_vars = name,
.smooth = FALSE,
.interactive = FALSE
) +
scale_colour_manual(values = c("red", "black")) +
geom_point(size = 0.5, aes(color=name)) +
scale_y_continuous(labels = scales::comma) +
scale_x_date(labels = scales::date_format(format = "%Y-%m")) +
labs(title = "코로나19 검사자와 확진자 추세")
plotly::ggplotly(covid_confirmed_g)2020-04-02 ~ 2020-04-06 사이 결측값이 있어 pad_by_time() 함수로 결측된 기간을 생성시키고 나서, ts_impute_vec() 함수로 선형보간(period = 1)을 통해 결측값을 채워넣는다.
covid_age_df <- covid_age_df %>%
group_by(날짜) %>%
timetk::summarise_by_time(.date_var = 날짜,
.by = "day",
확진자 = sum(확진자),
검사자 = sum(검사자)) %>%
ungroup() %>%
timetk::pad_by_time(.date_var = 날짜, .by = "day") %>%
mutate(확진자 = ts_impute_vec(확진자, period = 1),
검사자 = ts_impute_vec(검사자, period = 1))
covid_confirmed_clean_g <- covid_age_df %>%
group_by(날짜) %>%
timetk::summarise_by_time(.date_var = 날짜,
.by = "day",
확진자 = sum(확진자),
검사자 = sum(검사자)) %>%
ungroup() %>%
filter(날짜 < "2020-05-01") %>%
pivot_longer(-날짜) %>%
plot_time_series(.date_var = 날짜,
.value = value,
.color_var = name,
# .facet_vars = name,
.smooth = FALSE,
.interactive = FALSE
) +
scale_colour_manual(values = c("red", "black")) +
geom_point(size = 0.5, aes(color=name)) +
scale_y_continuous(labels = scales::comma) +
scale_x_date(labels = scales::date_format(format = "%Y-%m")) +
labs(title = "코로나19 검사자와 확진자 추세")
plotly::ggplotly(covid_confirmed_clean_g)데이터 정제 전략을 세웠다면 다음 단계로 데이터를 정제하여 저장시킨다.
covid_age_gender_clean_df <- covid_age_gender_df %>%
group_by(구분) %>%
timetk::pad_by_time(.date_var = 날짜, .by = "day") %>%
mutate(확진자 = ts_impute_vec(확진자, period = 1),
검사자 = ts_impute_vec(검사자, period = 1),
사망자 = ts_impute_vec(사망자, period = 1)) %>%
select(날짜, 구분, 검사자, 확진자, 사망자, 감염율, 치명율) %>%
ungroup
covid_age_gender_clean_df %>%
write_rds("data/covid_age_gender_clean.rds")
covid_age_gender_clean_df# A tibble: 2,949 x 7
날짜 구분 검사자 확진자 사망자 감염율 치명율
<date> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
1 2020-04-02 0-9 9825. 112 0 0.0114 0
2 2020-04-03 0-9 9925. 115. 0 NA NA
3 2020-04-04 0-9 10026. 118. 0 NA NA
4 2020-04-05 0-9 10127. 120. 0 NA NA
5 2020-04-06 0-9 10227. 123. 0 NA NA
6 2020-04-07 0-9 10328. 126 0 0.0122 0
7 2020-04-08 0-9 10413. 126 0 0.0121 0
8 2020-04-09 0-9 10407. 128 0 0.0123 0
9 2020-04-10 0-9 10488. 129 0 0.0123 0
10 2020-04-11 0-9 10484. 130 0 0.0124 0
# ... with 2,939 more rows
시도별 데이터를 지역별로 처리하기 위해 문자형으로 되어 있는 자료구조를 날짜형, 범주형, 숫자형으로 변환시키고 불필요한 데이터를 제거하고 결측값에 대한 시계열 전처리 작업을 수행한다.
library(tidyverse)
library(timetk)
sido_dat <- read_rds("data/covid_sido_orig.rds")
sido_daily_tbl <- sido_dat %>%
arrange(날짜) %>%
# 17개 시도만 추출 ----
filter(시도 %in% c("강원", "경기", "경남", "경북", "광주", "대구", "대전", "부산",
"서울", "세종", "울산", "인천", "전남", "전북", "제주", "충남", "충북")) %>%
# 시계열 날짜 자료형 변환 ----
mutate(날짜 = lubridate::ymd_hms(날짜) %>% as.Date(.)) %>%
# 숫자형 자료변환 ----
mutate(across(확진자:격리해제, .fns = as.numeric)) %>%
# 시도를 범주형으로 변환시킨 후에 인구수 기준으로 범주 정렬
mutate(시도 = factor(시도, levels = c("경기", "서울", "부산", "경남", "인천", "경북", "대구", "충남", "전남", "전북", "충북", "강원", "대전", "광주", "울산", "제주", "세종")))
# 결측값 일괄 처리를 위한 도움 함수
impute_na <- function(x) {
x <- ifelse(is.na(x), 0, x)
return(x)
}
# impute_na(sido_daily_tbl$확진자)
sido_daily_tbl <- sido_daily_tbl %>%
# 빠진 날짜 결측값 ----
pad_by_time(.date_var = 날짜, .by = "day") %>%
# 결측값 채워넣기 ----
fill(확진자:격리해제, .direction = "down") %>%
# 도움함수를 사용해서 모든 변수에 대해 NA 값을 0 으로 채워넣기
mutate(across(.cols = 확진자:격리해제, .fns = impute_na))
sido_daily_tbl %>%
write_rds("data/sido_daily_tbl.rds")10만명당 확진자 추세를 시도별로 시각화한다. 17개 시도이나 세종을 제외하여 인구수 기준 10만명당 확진자수를 시각화한다.
sido_daily_plotly <- sido_daily_tbl %>%
pivot_longer(- c(`날짜`, `시도`), names_to = "구분", values_to = "값") %>%
filter(구분 == "10만_발생률",
!시도 == "세종") %>%
plot_time_series(.date_var = 날짜,
.value = 값,
.facet_var = 시도,
.smooth = FALSE,
.line_color = "red",
.facet_ncol = 4,
.title = "시도별 10만명당 확진자수",
.interactive = FALSE)
sido_daily_g <- sido_daily_plotly +
scale_y_continuous(labels = scales::comma) +
scale_x_date(labels = scales::date_format(format = "%y-%m")) +
facet_wrap(~시도, scales = "fixed")
sido_daily_g %>%
plotly::ggplotly()데이터 과학자 이광춘 저작
kwangchun.lee.7@gmail.com